#!/usr/bin/env python
# coding=utf-8
from flask import Blueprint, current_app, jsonify, request, render_template, redirect, send_file, send_from_directory, url_for, session, make_response, flash
import time
import datetime
import json
import os
import chardet
import traceback
from flask_login import login_required, current_user
from fileshare.models import FileShare, FileInfo
from fileshare.extensions import db, csrf
from fileshare.file_utils import b64decode_, getFileSize, zip_, delete_, copy_, cut_, extract, getFilesSize
from fileshare.utils import redirect_back
import base64


file_bp = Blueprint('file', __name__)


@file_bp.route('/page', methods=['GET'])
@login_required
def page():
    return render_template('file/file.html',
                           workdir=base64.b64encode(
                               current_user.get_filenames_all().encode()).decode(),
                           sep=base64.b64encode(os.path.sep.encode()).decode())


# 返回文件目录
@csrf.exempt
@file_bp.route('/dir', methods=['POST'])
@login_required
def dir():
    response = {'status': False}
    try:
        path = b64decode_(request.values.get('path'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in path:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        files = sorted(os.listdir(path))
        dir_ = []
        file_ = []
        for i in files:
            try:
                i = os.path.join(path, i)
                if not os.path.isdir(i):
                    if os.path.islink(i):
                        fileLinkPath = os.readlink(i)
                        file_.append({
                            'fileName': i,
                            'fileSize': getFileSize(i),
                            'fileOnlyName': os.path.split(i)[1] + '-->' + fileLinkPath,
                            'fileMODTime': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.stat(i).st_mtime)),
                            'power': oct(os.stat(i).st_mode)[-3:],
                            'fileType': 'file'
                        })
                    else:
                        file_.append({
                            'fileName': i,
                            'fileSize': getFileSize(i),
                            'fileOnlyName': os.path.split(i)[1],
                            'fileMODTime': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.stat(i).st_mtime)),
                            'power': oct(os.stat(i).st_mode)[-3:],
                            'fileType': 'file'
                        })
                    # 添加到文件信息表
                    if not FileInfo.query.filter_by(
                            filepath=i, username=current_user.username).first():
                        file = FileInfo(filepath=i,
                                        filetypes=i,
                                        filename=os.path.split(i)[1],
                                        filesize=getFileSize(i),
                                        filemodtime=datetime.datetime.fromtimestamp(
                                            int(os.stat(i).st_mtime)),
                                        isfolder=False,
                                        power=oct(os.stat(i).st_mode)[-3:],
                                        username=current_user.username)
                        file.code = file.get_code()
                        db.session.add(file)
                        db.session.commit()
                else:
                    dir_.append({
                        'fileName': i,
                        'fileOnlyName': os.path.split(i)[1],
                        'fileSize': getFileSize(i),
                        'fileMODTime': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.stat(i).st_mtime)),
                        'power': oct(os.stat(i).st_mode)[-3:],
                        'fileType': 'dir'
                    })
            except Exception as e:
                db.session.rollback()
                current_app.logger.warning(str(e))
                continue
        response['data'] = dir_ + file_
        response['count'] = len(files)
        response['path'] = base64.b64encode(path.encode()).decode()
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 下载
@ csrf.exempt
@ file_bp.route('/download', methods=['GET'])
@ login_required
def download():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        if os.path.isdir(filename):
            if not os.path.exists(filename+'[打包下载].zip'):
                result = zip_(fileList=[filename],
                              zipPath=os.path.split(filename)[0])
                if result[0]:
                    filename = result[1]
                else:
                    flash(str(result[1]), 'warning')
                    return redirect_back()
            else:
                filename = filename+'[打包下载].zip'
        response = make_response(send_from_directory(os.path.split(
            filename)[0], os.path.split(filename)[1], as_attachment=True))
        response.headers["Content-Disposition"] = "attachment; filename={}".format(
            os.path.split(filename)[1].encode().decode('latin-1'))
        return response
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)


# 在线编辑
@ csrf.exempt
@ file_bp.route('/edit', methods=['POST', 'GET'])
@ login_required
def edit():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        if os.path.getsize(filename) > 2097152:
            response['msg'] = '不能在线编辑大于2MB的文件'
            response['code'] = 4000
            return jsonify(response)
        with open(filename, 'rb') as f:
            srcBody = f.read()
            char = chardet.detect(srcBody)
            fileCoding = char['encoding']
            if fileCoding == 'GB2312' or not fileCoding or fileCoding == 'TIS-620' or fileCoding == 'ISO-8859-9':
                fileCoding = 'GBK'
            if fileCoding == 'ascii' or fileCoding == 'ISO-8859-1':
                fileCoding = 'utf-8'
            if fileCoding == 'Big5':
                fileCoding = 'BIG5'
            if not fileCoding in ['GBK', 'utf-8', 'BIG5']:
                fileCoding = 'utf-8'
            try:
                fileCode = srcBody.decode(fileCoding).encode('utf-8')
            except Exception as e:
                current_app.logger.error(traceback.format_exc())
                # 这一步说明文件编码不被支持,可以按需修改返回数据
                response['data'] = str(srcBody)
                response['msg'] = str(e)+fileCoding
                response['code'] = 4000
                return jsonify(response)
            response['msg'] = fileCoding
            response['code'] = 0
            response['status'] = True
            response['data'] = fileCode.decode()
            return jsonify(response)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)


# 保存编辑后的文件
@ csrf.exempt
@ file_bp.route('/save', methods=['POST'])
@ login_required
def save():
    response = {'status': False}
    try:
        data = b64decode_(request.values.get('data'))
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(data)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['msg'] = str(e)
        response['code'] = 4000
        return jsonify(response)
    response['msg'] = 'success'
    response['code'] = 0
    response['status'] = True
    return jsonify(response)


# 删除
@ csrf.exempt
@ file_bp.route('/delete', methods=['POST'])
@ login_required
def delete():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        result = delete_(filename)
        if not result[0]:
            response['code'] = 4000
            response['msg'] = str(result[1])
            return jsonify(response)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 文件夹大小计算
@ csrf.exempt
@ file_bp.route('/size', methods=['POST'])
@ login_required
def size():
    response = {'status': False}
    try:
        path = b64decode_(request.values.get('path'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in path:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        size = getFilesSize(path)
        response['data'] = size
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 修改文件权限
@ csrf.exempt
@ file_bp.route('/chmod', methods=['POST'])
@ login_required
def chmod():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        power = request.values.get('power')
        # 修改权限
        os.chmod(filename, int(power, 8))
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 重命名
@ csrf.exempt
@ file_bp.route('/rename', methods=['POST'])
@ login_required
def rename():
    response = {'status': False}
    try:
        newfilename = b64decode_(request.values.get('newfilename'))
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        filepath = os.path.split(filename)[0]
        filename = os.path.split(filename)[1]
        if os.path.exists(os.path.join(filepath, newfilename)):
            response['msg'] = '文件名重复'
            return jsonify(response)
        # 修改文件名
        os.rename(os.path.join(filepath, filename),
                  os.path.join(filepath, newfilename))
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = "success!"
    return jsonify(response)


# 解压文件
@ csrf.exempt
@ file_bp.route('/unzip', methods=['POST'])
@ login_required
def unzip():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        extractResult = extract(filename)
        if not extractResult[0]:
            response['code'] = 4000
            response['msg'] = str(extractResult[1])
            return jsonify(response)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 图片转base64供前端浏览
@ csrf.exempt
@ file_bp.route('/preview', methods=['POST'])
@ login_required
def preview():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename', None))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in filename:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        with open(filename, 'rb') as f:
            imgBase64 = base64.b64encode(f.read()).decode()
        response['data'] = imgBase64
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 上传文件
@ csrf.exempt
@ file_bp.route('/upload', methods=['POST'])
@ login_required
def upload():
    response = {'status': False}
    try:
        path = b64decode_(request.values.get('path'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in path:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        f = request.files.get('file')
        f.save(os.path.join(path, f.filename))
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 创建目录
@ csrf.exempt
@ file_bp.route('/mkdir', methods=['POST'])
@ login_required
def mkdir():
    response = {'status': False}
    try:
        path = b64decode_(request.values.get('path'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in path:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        foldername = b64decode_(request.values.get('foldername'))
        if os.path.exists(os.path.join(path, foldername)):
            response['code'] = 4000
            response['msg'] = '目录已存在'
            return jsonify(response)
        else:
            os.mkdir(os.path.join(path, foldername))
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 创建文件
@ csrf.exempt
@ file_bp.route('/touch', methods=['POST'])
@ login_required
def touch():
    response = {'status': False}
    try:
        filename = b64decode_(request.values.get('filename'))
        path = b64decode_(request.values.get('path'))
        # 防止目录参数被串改
        if current_user.get_filenames_all() not in path:
            response['code'] = 4000
            response['msg'] = '请勿更改目录'
            return jsonify(response)
        if os.path.exists(os.path.join(path, filename)):
            response['code'] = 4000
            response['msg'] = '文件已存在'
            return jsonify(response)
        else:
            open(os.path.join(path, filename), 'w', encoding='utf-8')
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 拷贝文件
@ csrf.exempt
@ file_bp.route('/copy', methods=['POST'])
@ login_required
def copy():
    response = {'status': False}
    try:
        filenames = json.loads(request.values.get('filenames'))
        filenames = list(b64decode_(i) for i in filenames)
        session["filenames"] = filenames
        session['action'] = 'copy'
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 剪切文件
@ csrf.exempt
@ file_bp.route('/cut', methods=['POST'])
@ login_required
def cut():
    response = {'status': False}
    try:
        filenames = json.loads(request.values.get('filenames'))
        filenames = list(b64decode_(i) for i in filenames)
        session["filenames"] = filenames
        session['action'] = 'cut'
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 压缩文件
@ csrf.exempt
@ file_bp.route('/zip', methods=['POST'])
@ login_required
def zip():
    response = {'status': False}
    try:
        path = b64decode_(request.values.get('path'))
        filenames = json.loads(request.values.get('filenames'))
        filenames = list(b64decode_(i) for i in filenames)
        for i in filenames:
            # 防止目录参数被串改
            if current_user.get_filenames_all() not in i:
                response['code'] = 4000
                response['msg'] = '请勿更改目录'
                return jsonify(response)
        result = zip_(fileList=filenames, zipPath=path)
        if not result[0]:
            response['code'] = 4000
            response['msg'] = str(result[1])
            return jsonify(response)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 多选删除
@ csrf.exempt
@ file_bp.route('/deletes', methods=['POST'])
@ login_required
def deletes():
    response = {'status': False}
    try:
        filenames = json.loads(request.values.get('filenames'))
        filenames = list(b64decode_(i) for i in filenames)
        for i in filenames:
            # 防止目录参数被串改
            if current_user.get_filenames_all() not in i:
                response['code'] = 4000
                response['msg'] = '请勿更改目录'
                return jsonify(response)
            result = delete_(i)
            if not result[0]:
                response['code'] = 4000
                response['msg'] = str(result[1])
                return jsonify(response)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
    response['status'] = True
    response['code'] = 0
    response['msg'] = 'success'
    return jsonify(response)


# 粘贴
@ csrf.exempt
@ file_bp.route('/paste', methods=['POST'])
@ login_required
def paste():
    response = {'status': False}
    try:
        action = session['action']
        filenames = session["filenames"]
        path = b64decode_(request.values.get('path'))
        if action == 'cut':
            for cutFile in filenames:
                # 防止目录参数被串改
                if current_user.get_filenames_all() not in cutFile:
                    response['code'] = 4000
                    response['msg'] = '请勿更改目录'
                    return jsonify(response)
                result = cut_(cutFile, path)
                if not result[0]:
                    response['code'] = 4000
                    response['msg'] = str(result[1])
                    return jsonify(response)
            response['status'] = True
            response['code'] = 0
            response['msg'] = 'success'
            return jsonify(response)
        if action == 'copy':
            for copyFile in filenames:
                # 防止目录参数被串改
                if current_user.get_filenames_all() not in copyFile:
                    response['code'] = 4000
                    response['msg'] = '请勿更改目录'
                    return jsonify(response)
                result = copy_(copyFile, path)
                if not result[0]:
                    response['code'] = 4000
                    response['msg'] = str(result[1])
                    return jsonify(response)
            response['status'] = True
            response['code'] = 0
            response['msg'] = 'success'
            return jsonify(response)
        response['code'] = 4000
        response['msg'] = "未知请求"
        return jsonify(response)
    except Exception as e:
        current_app.logger.error(traceback.format_exc())
        response['code'] = 4000
        response['msg'] = str(e)
        return jsonify(response)
